<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ES6 helloWorld</title>

    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
    <script>
    const Jelly = {
        name: `Jelly`
        ,date: `2019-05-07`
        ,todos: [
            {name: `抽烟`, completed: false}
            ,{name: `喝酒`, completed: true}
            ,{name: `烫头`, completed: false}
        ]
    }
    </script>
</head>
<body>
    <div>
        <h1>看到31集</h1>

        <h1>开发技巧</h1>
        <div>
            1.js调试，直接敲debugger在你想要设断点的地方 <br/>
            2.控制台可以直接运行js语句 <br/>
            3.使用Error对象，然后return，可以准确的打印出发现错误的地方。
        </div>

        <h1>一、var、let、const</h1>
        <div>
            1.1 重复声明 <br/>
            var可以重复声明；let、const不可以重复声明，否则会报错: Identifier 'xxx' has already been declared <br/>
            所以在定义变量中，如果值可能会改变的就用let进行声明、如果值不会改变的就用const声明。尽量避免用var声明变量，因为可能会
            覆盖声明<br/>

            <br/>1.2 重复赋值<br/>
            const常量只能被赋值一次，类似于java的final; var、let可以被赋值多次<br/>
            所以const是用于定义常量的，并且永远不会改变的值<br/>

            <br/>1.3 作用域<br/>
            var是function scope；let、const是block scope <br/>
        </div>
    </div>
    <div>
        <h1>二、箭头函数 arrow function</h1>
        <div>
            2.1 箭头函数里的this指向父类
            <div id="arrowFuntion" style="width: 200px; height: 50px; background: skyblue;">点击我</div>
        </div>
    </div>

    <div>
        <h1>三、参数默认值</h1>
        <div>
            3.1
            <div id="defaultArgument" style="width: 200px; height: 50px; background: skyblue;">点击我</div>
        </div>
    </div>

    <div>
        <h1>四、模板字符串</h1>
        <div>
            <br/>4.1 定义方式的改变<br/>
            ES6中，新增了``这个符号来定义字符串，我们称之为模板字符串。并且模板字符串是可以嵌套使用的 <br/>
            模板字符串中，可以使用${}来取变量的值  <br/>
            这样就避免了以前的 '字符串' + 变量 + '字符串'这样很难看的定义方式。<br/>
            取而代之的是`字符串 ${变量} 字符串`这种定义方式，一目了然 <br/>
            
            <br/>4.2 demo1<br/>
            <div id="templetStringDemo1"></div>

            <br/>4.3 demo3<br/>
            <div id="templetStringDemo2"></div>

            <br/>4.4 标签模板字符串<br/>
            暂时跳过

            <br/>4.5 ES6新增的字符串函数<br/>
            startsWith、endsWith、includes、repeat

            <br/>总结<br/>
            `模板字符串的${}里面其实装的是js语句，所以即可以传变量，又可以调用方法 <br/>
            `在jsp中，${}会跟EL表达式冲突，所以在jsp中使用模板字符串，要对${}进行转义，写成\${}即可。参考博客：https://www.jianshu.com/p/a7f409cf9234


        </div>

        <h1>五、ES6 解构</h1>
        <div>
            <br/>5.1 对象解构<br/>
            这个就是一种语法糖，用于快速拿到对象的属性。最常用的地方应该是配置式接口 <br/>
            const {name : _name, date : _date, todos} = Jelly; <br/>
            
            <br/>5.2 数组解构<br/>

            <br/>5.2 For of loop<br/>
            JS的几种循环 <br/>
            1.普通的for(let i = 0; i < arr.length; i++); 这种方法比较繁琐，而且可读性不好<br/>
            2.数组的forEach + 箭头函数。这种方法不好的地方在于不能break或者isContinue <br/>
            3.for in。这种遍历方法只能遍历索引，可读性不好，而且会遍历出原型链或者变量的其他属性
            4.for of。好用，而且只会遍历数组本身。
        </div>

        <h1>六、新增关于数组的方法</h1>
        <div>
            Array.from(obj) 可以将一个类数组对象转换成数组对象
            Array.of(obj) 类似于java的Arrays.of，解决了new Array()参数不同行为不一致的问题
            arrayObj.find(Predicate filter) 接收一个Predicate，然后返回第一个找到的元素
            arrayObj.findIndex(Predicate filter) 接收一个Predicate，然后返回第一个找到的元素的索引
            arrayObj.some(Predicate filter) 数组里至少有一个满足Predicate的元素，则返回true；否则返回false
            arrayObj.every(Predicate filter) 数组里所有元素都要满足Predicate，则返回true；否则返回false
        </div>

        <h1>七、剩余参数与扩展运算符</h1>
        <div>
            <br/>7.1 剩余参数<br/>
            剩余参数，类似于java的可变参数。就是将剩余的参数 组合成一个数组，并且剩余参数只能作为最后一位参数 <br/>

            <br/>7.2 扩展运算符<br/>
            扩展运算符，其实就是剩余参数相反的意思。剩余参数是将其余的参数捆绑在一起变成一个数组；<br/>
            而扩展运算符其实是将 捆绑在一起的数组解绑成一个个对象。扩展运算符可以对“数组”、“类数组”使用 <br/>
            扩展预算符的实际作为大概为：多个数组的concat、数组的深拷贝
        </div>

        <h1>八、对象字面量</h1>
        <div>
            第二十五集，除了方法简写变得跟java一样了，其他没看懂
        </div>

        <h1>九、Promise</h1>
        <div>
            <br/>9.1 Promise是什么<br/>
            Promise的意思是承诺，承诺的意思是Promise不管把事情处理好了还是坏了，都会返回应该响应，这是它的承诺。 <br/>
            使用它的思路类似于：我现在要交一件事情给你做，好吧你做吧，我现在要去做其他事情，等你做好了在做我安排给你的下一件事情。<br/>
            
            <br/>9.2<br/>
            Promise.all()和Promise.race()<br/>
            Promise.all()：当all里面的所有Promise都返回resolve，才会执行then，否则执行error <br/>
            Promise.race(): 只执行第一个返回的Promise，当第一个返回的Promise返回resolve，则执行then，否则执行error  <br/>
        </div>

        <h1>十、Symbol</h1>
        <div>
            ES6前，js的6种数据类型：undefined, null, boolean, number, string, object <br/>
            ES6推出了第7种数据类型：Symbol <br/>
        </div>

        <h1>十一、ESLint</h1>
        跳过跳过

        <h1>十二、原型 和 类的拓展</h1>
        js中所有对象都有一个属性，__propt__，这个属性指向其所属的类型的原型对象（这个类似于java的Class），然后所有的类都继承原型的方法。

    </div>
    <div>
        补充：
        1.subString是切割字符串的，slice是切割数组的
        2.apply、call方法类似于反射，获取class对象，然后获取方法对象。然后传入实例和方法参数进行调用。
        
        var personClass = {
        fullName: function(city, country) {
            return this.firstName + " " + this.lastName + "," + city + "," + country;
        }
        }
        var person1 = {
        firstName:"Bill",
        lastName: "Gates"
        }
        var x = personClass.fullName.apply(person1, ["Seatle", "USA"]); 
        document.getElementById("demo").innerHTML = x; 

    </div>

    <script>
        // 9.1
        // github API 官方文档 ：https://developer.github.com/v4/
        // axios请求为什么是同步的
        // const users = axios.get("https://api.github.com/users"); //resful风格
        // console.info(users);
        // console.info("123");
        
        // $.get("https://api.github.com/users", {}, function(response){
        //     console.info(response);
        // });
        // console.info("123");

        // new Promise((resolve, reject) => {
        //     resolve(axios.get("https://api.github.com/users"));
        // })
        // .then(data => console.log(data))
        // .catch(err => console.log(Error(err)));
        // console.info("123");


        // 9.2 自定义Promise
        // const p = new Promise((resolve, reject) => {
        //     console.info('setTimeout外部'); //不管用没有使用then，只要new出来Promise，Promise内部都会执行
        //     //setTimeout模拟Http请求
        //     setTimeout(() => {
        //         //reject(Error('hello Promise')); //使用Error对象可以打印出真正发送错误的行数
        //         resolve('hello Promise');
        //         console.info('setTimeout内部');
        //     }, 2000);
        // });
        // p.then(data => console.log(data))
        //     .catch(err => console.error(err))
        // console.info("123");

        // 9.3 处理多个Promise
        const usersPromise = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(['jelly', 'may']);
            }, 2000);
        });
        const fruitPromise = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(['apple', 'banana']);
            }, 1000)
        });

        Promise
            .all([usersPromise, fruitPromise])
            //.race([usersPromise, fruitPromise])
            .then(response => {
                const [uses, fruit] = response;
                console.log(uses);
                console.log(fruit);
            });


        // 7.1 剩余参数
        // 玩家姓名 ...分数
        // let record = ['marry', 95, 98, 92];
        // let [playerName, ...score] = record; //数组解构 + 剩余参数
        // console.info(playerName, score);

        // 7.2 扩展运算符
        let arr1 = [1, 2, 3];
        let arr2 = [5, 6, 7];
        let num = 4;

        // 需求：现在要把arr1和arr2拼接起来，并且中间插入num，拼接完的结果如下所示：
        // [1, 2, 3, 4, 5, 6, 7]
        // 传统方法
        // arr1.push(num);
        // let result = arr1.concat(arr2);

        //捆绑运算符
        // let result = [...arr1, num, ...arr2];
        // console.info(result);

        // 需求：根据数组，创建一个Date
        let dateArr = [2019, 9, 19];

        // 传统方法
        //console.info(new Date(dateArr[0], dateArr[1], dateArr[2]));

        // ES6方法
        // console.info(new Date(...dateArr));

        // 5.2
        const fruits = ['Apple', 'Banana', 'Orange', 'Mango'];
        // for(let i = 0; i < fruits.length; i++){
        //     let fruit = fruits[i];
        //     console.info(fruit);
        // }

        // fruits.forEach(fruit => console.info(fruit))

        // for(let index in fruits){
        //     console.info(fruits[index]);
        // }

        // for(let fruit of fruits){
        //     if(fruit == 'Orange') continue;
        //     console.info(fruit);
        // }

        // 5.1
        const {name : _name, date : _date, todos} = Jelly;
        // console.info(_name);
        // console.info(_date);
        // console.info(todos);

        // 4.5
        const id = `440105199604015714`;
        const fan = `I love Laravist`;
        id.startsWith("44010", 0);
        fan.endsWith("vist");
        id.includes(1996);
        '哈'.repeat(10)

        // 4.3
        const template2 = `
            <ul>
                ${renderTodos(Jelly.todos)}
            </ul>
        `;
        document.getElementById(`templetStringDemo2`).innerHTML = template2;

        function renderTodos(todos){
            return todos.map(todo =>
                `<li>
                    人生三大乐事 ${todo.name} ${todo.completed ? '昨晚做了' : '今晚做'}
                </li>`
            ).join("")
        };

        // 4.2
        const template = `
            <ul>
                ${Jelly.todos.map(todo =>
                    `<li>
                        人生三大乐事 ${todo.name} ${todo.completed ? '昨晚做了' : '今晚做'}
                    </li>`
                ).join("")}
            </ul>
        `;
        document.getElementById(`templetStringDemo1`).innerHTML = template;

        //-------------------------------- 我是分隔符 --------------------------------
        //3.1
        let defaultArgument = document.getElementById(`defaultArgument`);
        defaultArgument.onclick = function(){
            func();
            func(undefined, `你好`); //如果第一个参数想使用默认值，第二个参数想用传入的值，那么第一个参数得显示执行undefined
            func(`ES6`, `真强`);
        }
        function func(param1 = `hello`, param2 = `world`){
            // 默认底层是使用typeof param1 === `undefined`来判断是否使用默认值的
            // console.info(typeof param1 === `undefined` );

            // 旧式写法
            // if(!param1) param1 = `hello`;
            // if(!param2) param1 = `world`;
            console.info(`${param1} ${param2}`);
        }

        //-------------------------------- 我是分隔符 --------------------------------
        //2.1
        let arrowFuntion = document.getElementById(`arrowFuntion`);
        arrowFuntion.onclick = function(){
            console.info(this);
        }

        //箭头函数this指向父类，即window
        // arrowFuntion.onclick = () => {
        //     console.info(this);
        // }

        //-------------------------------- 我是分隔符 --------------------------------
        // 1.1 重复声明
        // var v1 = `v1`;
        // var v1 = `v1`;
        // let v2 = `v2`;
        // const v3 = `v3`;

        // 1.2 重复赋值
        // var v1 = `v1`;
        // let v2 = `v2`;
        // const v3 = `v3`;
        // v1 = `v1`;
        // v2 = `v2`;
        // v3 = `v3`;

        // 1.3 作用域
        // {
        //     var v1 = `v1`;
        //     let v2 = `v2`;
        //     const v3 = `v3`;
        // }
        // {
        //     console.info(`${v1}`);
        //     console.info(`${v2}`)
        //     console.info(`${v3}`)
        // }

    </script>

    

</body>
</html>